package com.yxplearn.mybatisplus.manager;

import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;

import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 供游戏内获取各种数据: 服务service, 数据管理器manager, 缓存数据cachedData
 *
 * @author xiezuojie
 */
@Component
public final class GameExplorer implements ApplicationContextAware {

    public static EntityCacheManager cm = new MemoryCacheManager();

    static Map<Long, LocalPlayerId> localPlayerIds = new ConcurrentHashMap<>(2048);

    public static LocalPlayerId putLocalPlayerId(long playerId) {
        LocalPlayerId localPId = new LocalPlayerId();
        localPId.playerId = playerId;
        LocalPlayerId prev = localPlayerIds.putIfAbsent(playerId, localPId);
        if (prev != null) {
            localPId = prev;
        }
        return localPId;
    }

    public static LocalPlayerId getLocalPlayerId(long playerId) {
        return localPlayerIds.get(playerId);
    }

    public static boolean hasLocalPlayer(long playerId) {
        return localPlayerIds.containsKey(playerId);
    }

    private static class LocalPlayerId {
    	long playerId;
    }

    /**
     * 从缓存获取实体,在缓存未获取到实体时,将从数据库读取数据并放到缓存
     * <p>
     * {@link MemoryCacheManager#getEntity(int, Class)}
     *
     * @param playerId
     * @param clazz
     * @return 缓存实体, 如果这个玩家不存在, 那么返回null, 否则, 返回已存在的缓存内实体, 没有则返回null
     */
    public static <T extends PersistEntity> T getEntity(long playerId, Class<T> clazz) {
        if (!localPlayerIds.containsKey(playerId)) {
            return null;
        }
        return cm.getEntity(playerId, clazz);
    }

    /**
     * @param playerId
     * @param clazz
     * @return 缓存实体, 如果这个玩家不存在, 那么返回null, 否则, 返回已存在的缓存内实体, 没有则返回null
     */
    public static <T extends PersistEntity> T getEntityIfExisting(int playerId, Class<T> clazz) {
        if (!localPlayerIds.containsKey(playerId)) {
            return null;
        }
        return cm.getEntityFromCache(playerId, clazz);
    }

    /**
     * @param playerId
     * @return 缓存实体集, 如果这个玩家不存在, 那么返回null, 否则, 返回已存在的缓存内实体集, 没有则返回null
     */
    public static Entities getEntitiesIfExisting(int playerId) {
        if (!localPlayerIds.containsKey(playerId)) {
            return null;
        }
        return cm.getEntitiesIfExisting(playerId);
    }

    /**
     * @return 所有实体列表, 在外部不改变列表结构的情况下这个列表的内部结构不会发生变化
     */
    public static List<Entities> getAllEntities() {
        return cm.getAllEntities();
    }

    /**
     * 删除与指定玩家相关的所有缓存，删除会同时调用保存数据
     *
     * @param playerId
     */
    public static void removeEntities(int playerId) {
        // 删除顺序重要，不要轻易改变
        localPlayerIds.remove(playerId);
        CachedDataPersistService.saveSingleAndRemove(playerId);
        return;
    }

//    public static class Services {
//        public static TeamService teamService;
//    }

    public static class Managers {
        public static UserMapperManager userMapperManager;
    }

    protected static ApplicationContext context;

    public static <T> T getBean(Class<T> clazz) {
        return context.getBean(clazz);
    }

    public static Object getBean(String str) {
        return context.getBean(str);
    }

    @Override
    public void setApplicationContext(ApplicationContext ctx) throws BeansException {
        context = ctx;
        Managers.userMapperManager = ctx.getBean(UserMapperManager.class);
    }

    /**
     * 添加到全服玩家ID
     *
     * @param playerId
     */
    public static void addGlobalPlayerId(int playerId) {
    }

    /**
     * 检查是否存在指定玩家,全服唯一
     *
     * @param playerId
     * @return 是否存在指定玩家ID的玩家, true存在, false不存在
     */
    public static boolean isPlayerExisting(int playerId) {
        return localPlayerIds.containsKey(playerId);
    }

    /**
     * 添加到全服玩家Name
     *
     * @param playerName
     * @param playerId
     * @return 添加是否成功, 当要添加的名字已存在时添加失败, 返回false
     */
//    public static boolean addGlobalPlayerNameID(String playerName, int playerId) {
//        Optional<Boolean> boolOpt = RedissonUtil.hSetNX(RedisKeys.Public.PLAYER_NAME__ID, playerName, playerId);
//        return boolOpt.orElse(false);
//    }

    /**
     * 修改名字
     *
     * @param oldName    曾用名
     * @param playerName 新名字
     * @param playerId   角色id
     * @return
     */
//    public static boolean changeGlobalPlayerNameID(String oldName, String playerName, int playerId) {
//        Optional<Boolean> boolOpt = RedissonUtil.hSetNX(RedisKeys.Public.PLAYER_NAME__ID, playerName, playerId);
//        if (boolOpt.isPresent()) {
//            RedissonUtil.hDel(RedisKeys.Public.PLAYER_NAME__ID, oldName);
//            return true;
//        }
//        return false;
//    }

    /**
     * 检查是否存在指定玩家,全服唯一
     *
     * @param playerName
     * @return 是否存在指定玩家Name的玩家, true存在, false不存在
     */
//    public static boolean isPlayerExisting(String playerName) {
//        Optional<Integer> intOpt = RedissonUtil.hGet(RedisKeys.Public.PLAYER_NAME__ID, playerName);
//        if (intOpt.isPresent()) {
//            return true;
//        }
//
//        try {
//            int present = Managers.playerManager.getIdByName(playerName);
//            if (present > 0) {
//                RedissonUtil.hSet(RedisKeys.Public.PLAYER_NAME__ID, playerName, present);
//                return true;
//            }
//        } catch (Exception e) {
//            return true;
//        }
//
//        return false;
//    }
}
